package com.vdongchina.thread.Lock;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 重入锁 reentrantlock
 * 线程可以重入 : 锁可以再次获取锁, 锁可以一层一层的释放锁
 * 线程公平与非公平
 */
public class ReentrantLockDemo {

    //公平锁
    private static Lock fairLock = new ReentrantLock2(true);
    //非公平锁
    private static Lock unfairLock = new ReentrantLock2(false);

    static CountDownLatch start = new CountDownLatch(1);

    /**
     * 重入锁默认为什么是非公平锁, 且开销小
     *  因为公平锁每次切换上下文都是一次开销,且不重入
     *  而非公平锁会优先自己获取锁,所以上下文切换的次数较少,开销较小,重入率高
     * @param args
     */
    public static void main(String[] args) {
        //testLock(fairLock);
        //非公平锁在释放锁的时候会再次竞争锁,且获取的概率非常大,会造成线程"饥饿"
         testLock(unfairLock);
    }

    private static void testLock(Lock reentrantLock) {

        for (int i = 0; i < 5; i++) {
            Thread thread = new Job(reentrantLock);
            thread.setName("线程-" + i);
            thread.start();
        }
        start.countDown(); //达到0 ,所有的await()会同时执行

    }

    private static class Job extends Thread {
        private Lock lock;

        public Job(Lock lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                start.await();
            } catch (InterruptedException e) {
            }
            for (int i = 0; i < 2; i++) {
                lock.lock();
                try {
                    System.out.println("Lock by [" + getName() + "], Waiting by " + ((ReentrantLock2) lock).getQueuedThreads());
                } finally {
                    lock.unlock();
                }
            }
        }

    }

    private static class ReentrantLock2 extends ReentrantLock {

        public ReentrantLock2(boolean fair) {
            super(fair);
        }
        @Override
        public Collection<Thread> getQueuedThreads() {
            List<Thread> arrayList = new ArrayList<>(super.getQueuedThreads());
            Collections.reverse(arrayList);
            return arrayList;
        }
    }


}
